//! @Author: DengLibin
//! @Date: Create in 2024-01-17 18:26:52
//! @Description: csp  接口 进行rsa加密和解密

#[cfg(windows)]
extern crate winapi;

use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::FormatMessageA;
use winapi::um::winbase::FORMAT_MESSAGE_ALLOCATE_BUFFER;
use winapi::um::winbase::FORMAT_MESSAGE_FROM_SYSTEM;
use winapi::um::wincrypt::CryptAcquireContextA;

use winapi::um::wincrypt::CryptReleaseContext;

use winapi::um::wincrypt::HCRYPTPROV;

use winapi::shared::minwindef::BOOL;


use winapi::um::winnt::LANG_NEUTRAL;
use winapi::um::winnt::MAKELANGID;
use winapi::um::winnt::SUBLANG_DEFAULT;


use rust_common::base64;
use winapi::{
    shared::winerror::{
        ERROR_BUSY, ERROR_NOT_ENOUGH_MEMORY, NTE_BAD_FLAGS, NTE_BAD_KEYSET, NTE_KEYSET_ENTRY_BAD,
        NTE_KEYSET_NOT_DEF, NTE_NO_MEMORY, NTE_PROV_DLL_NOT_FOUND,
    },
    um::wincrypt::{CryptDecrypt, CryptGetUserKey, AT_KEYEXCHANGE, HCRYPTKEY},
};

// CSP(加密服务提供商名称)
const PROVIDER_NAME: &str = "EnterSafe ePass3000GM CSP v1.0";

const CONTAINER: &str = "yiscn";

/// @Author: DengLibin
/// @Date: Create in 2024-01-18 11:12:43
/// @Description: rsa加解密
#[cfg(windows)]
pub fn hello_dcrypt() {
    use winapi::um::wincrypt::{CryptDestroyKey, PROV_RSA_FULL};

    let mut sz_provider = PROVIDER_NAME.as_bytes().to_vec();
    //加一个0结尾
    sz_provider.push(0);

    //转i8
    let provider_str = sz_provider
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let provider = provider_str.as_ptr();
    //清理
    drop(sz_provider);

    let mut sz_container = CONTAINER.as_bytes().to_vec();
    //加一个0结尾
    sz_container.push(0);

    //转i8
    let sz_container_str = sz_container
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let sz_container_p = sz_container_str.as_ptr();
    //清理
    drop(sz_container);

    unsafe {
        // 定义加密上下文句柄
        let mut hprov: HCRYPTPROV = 0;
        let hp = &mut hprov;
        //获取上下文句柄
        let b: BOOL = CryptAcquireContextA(hp, sz_container_p, provider, PROV_RSA_FULL, 0);
        println!("初始化上下文结果：{},句柄:{}", b, *hp);

        let success: bool = b != 0;
        if !success {
            let error_code = GetLastError();
            if error_code as i32 == NTE_BAD_KEYSET {
                println!("无法打开密钥容器或容器不存在");
            } else if error_code == ERROR_NOT_ENOUGH_MEMORY {
                println!("操作系统在操作期间内存不足");
            } else if error_code == ERROR_BUSY {
                println!("另一个线程或进程正在使用此密钥容器");
            } else if error_code as i32 == NTE_KEYSET_ENTRY_BAD {
                println!("找到 pszContainer 密钥容器，但已损坏");
            } else if error_code as i32 == NTE_KEYSET_NOT_DEF {
                println!("请求的提供程序不存在。");
            } else if error_code as i32 == NTE_NO_MEMORY {
                println!("CSP 在操作期间内存不足。");
            } else if error_code as i32 == NTE_PROV_DLL_NOT_FOUND {
                println!("提供程序 DLL 文件不存在或不在当前路径上。");
            } else if error_code as i32 == NTE_BAD_FLAGS {
                println!("dwFlags 参数的值无效。");
            } else
            //容器已存在
            if error_code == 0x8009000F {
                println!("容器已存在:{}", CONTAINER);
            }
        }

        // 成功
        if success {
            //获取加密key
            let mut h_key: HCRYPTKEY = 0;

            if CryptGetUserKey(hprov, AT_KEYEXCHANGE, &mut h_key) == 0 {
                println!("获取加密key错误");
                show_error();
            } else {
                println!("获取加密key成功:{}", h_key);
            }
            let mut content = base64::decode_to_bytes("CPDwNqUOqQDOhpyymwZv+DCE3p+ck+rHzO/r7r+hu2ZdaklqkixDX2vfbE3l9eIscLsqoTgXHsH0UgAGISsgXmVJgQn06v296X0Be3VshF44PndPeXNOHo2H9yS1vat+KDmOASnAY8OOTwoknvxsmPAkUWJDqwf4D+a0Jpn5PzERLYHfvErWhBLfbNjLMiGsLBXg2IrlMu2/h94xMQ1i6n7Nu/GTEHn7pdd0RzVsymNnsK9RZLvhaxgBBc+sOwEwei6PnR9VSqY/LdfvB1DWV1hVmXNslQCaHdRB1q2AybIlGYiiqEZn/wh9ig/RA5EH0Robts0LqOAihsM7tTeptQ==").unwrap();
            let mut data_len = content.len() as u32;

            if CryptDecrypt(h_key, 0, 1, 0, content.as_mut_ptr(), &mut data_len) == 0 {
                println!("解密数据错误");
                show_error();
            } else {
                let s = &content[0..data_len as usize];
                let content = std::str::from_utf8(s).unwrap();
                println!("解密数据成功:{}", content);
            }

            println!("释放加密key句柄");
            if CryptDestroyKey(h_key) == 0 {
                println!("释放加密key句柄失败");
                show_error();
            } else {
                println!("释放加密Key句柄成功");
            }

            let b: BOOL = CryptReleaseContext(hprov, 0);
            println!("释放结果:{}", b);
        } else {
            println!("获取上下文句柄错误");
            show_error();
        }
    }
}
#[allow(dead_code)]
fn show_error() {
    unsafe {
        let error_code = GetLastError();
        println!("出错了:错误码:{0:#x}", error_code);

        let mut buffer = vec![0; 100];

        let dw_language_id = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as u32;
        //MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as u32
        let r = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            core::ptr::null_mut(),
            error_code,
            dw_language_id,
            buffer.as_mut_ptr(),
            0,
            core::ptr::null_mut(),
        );
        let buf = buffer.iter().map(|i| *i as u8).collect::<Vec<u8>>();
        println!(
            "错误信息:{}",
            std::str::from_utf8(&buf[..r as usize]).unwrap()
        );
    }
}
